#include "base_follow.h"
#include "cfg.h"
#include "str_util.h"

using namespace std;
using namespace lc;
using namespace su;
using namespace proto;

namespace
{
	static const uint32 CMD_VERIFY = ((uint32)BF_SVR1 << 16) | 1;
	static const uint32 CMD_MSG = ((uint32)BF_SVR1 << 16) | 2;
	static const uint32 CMD_BEAT_REQ = 3;
	static const uint32 CMD_BEAT_RSP = 4;
	static const uint32 CMD_BROADCAST = 5;
	static const uint32 CMD_BROADCAST_PART = 6;
	static const uint32 CMD_SVR1_MSG = ((uint32)BF_SVR1 << 16) | 10;
	static const uint32 CMD_SVR2_MSG = ((uint32)BF_SVR2 << 16) | 10;
	static const uint32 CMD_SVR3_MSG = ((uint32)BF_SVR3 << 16) | 10;
}

BaseFlowClient::BaseFlowClient(BaseFunTestMgr& mgr)
	:m_mgr(mgr)
{
	m_state = State::WAIT_SVR_REG;
}

void BaseFlowClient::SendVerify()
{
	UNIT_ASSERT(IsConnect());
	UNIT_ASSERT(State::WAIT_SVR_REG == m_state);
	SendStr(CMD_VERIFY, "verify");
	m_state = State::WAIT_VERFIY_RSP;
}

void BaseFlowClient::OnRecv(const lc::MsgPack& msg)
{
	UNIT_ASSERT(msg.len >= sizeof(uint32));
	string str;
	uint32 cmd = 0;
	{
		cmd = *((const uint32*)msg.data);
		const char* msg_str = msg.data + sizeof(uint32);
		uint32 msg_len = msg.len - sizeof(uint32);
		str.append(msg_str, msg_len);
	}
	if (CMD_VERIFY == cmd) //verify rsp
	{
		UNIT_ASSERT(State::WAIT_VERFIY_RSP == m_state);
		UNIT_ASSERT(string("verify_ok") == str);
		SendStr(CMD_MSG, "msg");
		m_state = State::WAIT_SVR_RSP;
		return;
	}
	else if (CMD_MSG == cmd)
	{
		UNIT_ASSERT(State::WAIT_SVR_RSP == m_state);
		UNIT_ASSERT(string("msg") == str);
		DisConnect();
		m_state = State::END;
	}
	else
	{
		UNIT_ERROR("unknow cmd=%d", cmd);
		UNIT_ASSERT(false);
	}
}

void BaseFlowClient::OnConnected()
{

}

void BaseFlowClient::OnDisconnected()
{

}



BaseFlowSvr::BaseFlowSvr(BaseFunTestMgr& mgr)
	:m_mgr(mgr)
{
	m_state = State::WAIT_SVR_REG;
}

void BaseFlowSvr::OnRegOK(uint32_t accId)
{
	if (accId != 0)
	{
		return;
	}
	UNIT_ASSERT(State::WAIT_SVR_REG == m_state);
	m_state = State::WAIT_CLIENT_REQ_VERFIY;
	m_mgr.m_client.SendVerify();
	UNIT_INFO("reg ok");
}

void BaseFlowSvr::OnRevVerifyReq(const SessionId& id, uint32 cmd, const std::string& msg)
{
	UNIT_ASSERT(id.cid != 0);
	UNIT_ASSERT(id.accId == 0);
	//	UNIT_INFO("cmd=%x", cmd);
	UNIT_ASSERT(CMD_VERIFY == cmd);
	UNIT_ASSERT(State::WAIT_CLIENT_REQ_VERFIY == m_state);
	UNIT_ASSERT(msg == "verify");
	string rsp_msg = "verify_ok";

	ADFacadeMgr::Ins().NtfVerifyRet(id, true);
	ADFacadeMgr::Ins().CreateSession(id, nullptr);
	id.SendToClient(CMD_VERIFY, rsp_msg);
	m_state = State::WAIT_CLIENT_MSG;

}

void BaseFlowSvr::OnRevClientMsg(const Session& session, uint32 cmd, const std::string& msg)
{
	UNIT_ASSERT(CMD_MSG == cmd);
	UNIT_ASSERT(State::WAIT_CLIENT_MSG == m_state);
	UNIT_ASSERT(msg == "msg");
	session.SendToClient(cmd, msg);
	m_state = State::WAIT_CLIENT_DISCON;
}

void BaseFlowSvr::OnClientDisCon(const proto::Session& sn)
{
	UNIT_ASSERT(sn.id.cid != 0);
	UNIT_ASSERT(sn.id.accId == 0);
	UNIT_ASSERT(State::WAIT_CLIENT_DISCON == m_state);
	m_state = State::END;

	UNIT_ASSERT(BaseFlowClient::State::END == m_mgr.m_client.m_state);
	UNIT_INFO("-----end--------");
	EventMgr::Ins().StopDispatch();
}

//void BaseFlowSvr::OnClientConnect(const Session &session)
//{
//	UNIT_ASSERT(State::WAIT_CLIENT_MSG == m_state);
//}



BaseFunTestMgr::BaseFunTestMgr()
	:m_client(*this)
	, m_svr(*this)
	, m_h_client(*this)
	, m_hSvr(*this)
	, m_bd_client({ *this,*this,*this })
	, m_bd_svr(*this)
	, m_route_svr1(*this)
	, m_route_svr2(*this)
	, m_route_client(*this)

{
	m_state = State::RUN_NONE;
}

bool BaseFunTestMgr::Init()
{
	const std::vector<AccAddr>& vecAccAddr = CfgMgr::Ins().m_inner_vec;
	const std::vector<AccAddr>& ex_vec = CfgMgr::Ins().m_ex_vec;
	UNIT_ASSERT(vecAccAddr.size() > 1);
	UNIT_ASSERT(ex_vec.size() > 1);
	AccAddr ex_addr = ex_vec[0];
	auto vec = vecAccAddr;
	vec.resize(1);

	AdFacadeInitData d;
	d.vecAccAddr = vecAccAddr;
	d.mainCmd = d.svrId = 1;
	d.isVerifySvr = true;
	//各种情况只能独立一个进程运行
	if (CfgMgr::Ins().m_svrType == "svr1")
	{
		UNIT_ASSERT(ADFacadeMgr::Ins().Init(m_svr, d));
		UNIT_ASSERT(m_client.ConnectInit(ex_addr.ip.c_str(), ex_addr.port));
	}
	else if (CfgMgr::Ins().m_svrType == "svr2")
	{
		UNIT_ASSERT(ADFacadeMgr::Ins().Init(m_hSvr, d));
		StartHeartbeatTest();
	}
	else if (CfgMgr::Ins().m_svrType == "svr3")
	{
		UNIT_ASSERT(ADFacadeMgr::Ins().Init(m_bd_svr, d));
		StartCheckBD(); 
	}
	else if (CfgMgr::Ins().m_svrType == "svr4_1") //必须先启动 svr4_1 再启动svr4_2
	{
		m_route_svr1.m_svr_id = 1;
		d.vecAccAddr = vecAccAddr;
		d.mainCmd = BF_SVR1;
		d.svrId = 1;
		d.isVerifySvr = true;
		UNIT_ASSERT(ADFacadeMgr::Ins().Init(m_route_svr1, d));
		m_state = State::RUN_ROUTE;
		UNIT_INFO("start RUN_ROUTE svr4_1");
	}
	else if (CfgMgr::Ins().m_svrType == "svr4_2")
	{
		m_route_svr2.m_svr_id = 2;
		d.vecAccAddr = vecAccAddr;
		d.mainCmd = BF_SVR1;
		d.svrId = 2;
		d.isVerifySvr = false;
		UNIT_ASSERT(ADFacadeMgr::Ins().Init(m_route_svr2, d));
		m_state = State::RUN_ROUTE;
		UNIT_INFO("start RUN_ROUTE svr4_2");
		static lc::Timer tm;
		tm.Start(1, [this]() {
			m_route_client.Start();
			});

		static lc::Timer tm2;
		tm2.Start(2, [this]() {
			UNIT_ASSERT(RouteSvr::State::START == m_route_svr2.m_state);
			m_route_svr2.m_state = RouteSvr::State::WAIT_ROUE_MSG_TO_SVR2;
			ADFacadeMgr::Ins().CreateSession(m_route_client.m_snId, [this](const Session* sn)
				{
					m_route_svr2.m_isCreateSn = true;
				});
			m_route_client.SendStr(CMD_SVR1_MSG, "msg2");
			});

		static lc::Timer endtm;
		endtm.Start(5, [this]() {
			UNIT_ASSERT(m_route_svr2.m_isCreateSn);
			UNIT_ASSERT(m_route_svr2.m_state == RouteSvr::State::END);
			UNIT_INFO("------------end---------");
			EventMgr::Ins().StopDispatch();
			});
	}
	else
	{
		UNIT_ERROR("unknow svrType=%s", CfgMgr::Ins().m_svrType.c_str());
		UNIT_ASSERT(false);
	}
	return true;

}

void BaseFunTestMgr::StartHeartbeatTest()
{
	UNIT_INFO("start heartbeat test");
	UNIT_ASSERT(m_state == State::RUN_NONE);
	m_state = State::RUN_HEARTBEAT;
	m_hSvr.Start();

	//delay start client
	auto f = [&]()
	{
		const std::vector<AccAddr>& ex_vec = CfgMgr::Ins().m_ex_vec;
		UNIT_ASSERT(ex_vec.size() > 1);
		UNIT_ASSERT(m_h_client.ConnectInit(ex_vec[0].ip.c_str(), ex_vec[0].port));
		UNIT_INFO("delay 1sec, start m_h_client connect");
	};
	m_tm.Stop();
	m_tm.Start(1 * 1000, f);

	auto f2 = [this]()
	{
		UNIT_ASSERT(m_h_client.m_state == HeartBeatClient::State::END);
		UNIT_ASSERT(m_hSvr.m_state == HeartBeatSvr::State::END);
		UNIT_INFO("--------end--------");
		EventMgr::Ins().StopDispatch();
	};
	m_endtm.Start(8 * 1000, f2);
}



void BaseFunTestMgr::StartCheckBD()
{
	m_state = State::RUN_BROADCAST_DISCON;
	//delay start client
	auto f = [&]()
	{
		m_bd_svr.Start();
	};
	m_tm.Stop();
	m_tm.Start(1 * 1000, f);
}


void BaseClient::SendStr(uint32 cmd, const std::string& msg)
{
	string pack;
	pack.append((const char*)&cmd, sizeof(cmd));
	pack.append(msg);
	SendPack(pack);
}

void BaseClient::OnRecv(const lc::MsgPack& msg)
{
	UNIT_ASSERT(msg.len >= sizeof(uint32));
	string str;
	uint32 cmd = 0;
	{
		cmd = *((const uint32*)msg.data);
		const char* msg_str = msg.data + sizeof(uint32);
		uint32 msg_len = msg.len - sizeof(uint32);
		str.append(msg_str, msg_len);
	}
	OnRecvMsg(cmd, str);
}

HeartBeatClient::HeartBeatClient(BaseFunTestMgr& mgr)
	:m_mgr(mgr)
{
	m_state = State::WAIT_VERFIY_RSP;
}

void HeartBeatClient::OnRecvMsg(uint32 cmd, const std::string& msg)
{
	if (CMD_VERIFY == cmd)
	{
		UNIT_ASSERT(m_state == State::WAIT_VERFIY_RSP);
		UNIT_INFO("HeartBeatClient verify ok, send beat");
		SendStr(CMD_BEAT_REQ, "");
		m_state = State::WAIT_BEAT_RSP;
	}
	else if (CMD_BEAT_RSP == cmd)
	{
		UNIT_INFO("rev beat rsp");
		UNIT_ASSERT(m_state == State::WAIT_BEAT_RSP);
		m_state = State::WAIT_DISCONNECTED;
	}
	else
	{
		UNIT_INFO("unknow cmd =%x", cmd);
		UNIT_ASSERT(false);
	}
}


void HeartBeatClient::OnConnected()
{
	UNIT_ASSERT(m_state == State::WAIT_VERFIY_RSP);
	SendStr(CMD_VERIFY, "verify");
	UNIT_INFO("client send verify req");
}

void HeartBeatClient::OnDisconnected()
{
	UNIT_ASSERT(m_state == State::WAIT_DISCONNECTED);
	m_state = State::END;
	UNIT_INFO("client beat timeout, disconnted");
}

HeartBeatSvr::HeartBeatSvr(BaseFunTestMgr& mgr)
	: m_mgr(mgr)
{
	m_state = State::WAIT_VERFIY_REQ;
}

void HeartBeatSvr::Start()
{
	UNIT_ASSERT(m_state == State::WAIT_VERFIY_REQ);
	UNIT_INFO(" HeartBeatSvr::Start");
	AccSeting seting;
	seting.hbi.req_cmd = CMD_BEAT_REQ;
	seting.hbi.rsp_cmd = CMD_BEAT_RSP;
	seting.hbi.interval_sec = 2;
	ADFacadeMgr::Ins().SetAccSeting(seting);
}

void HeartBeatSvr::OnRegOK(uint32_t svrId)
{

}

void HeartBeatSvr::OnRevClientMsg(const Session& session, uint32 cmd, const std::string& msg)
{

}

void HeartBeatSvr::OnRevVerifyReq(const SessionId& id, uint32 cmd, const std::string& msg)
{
	UNIT_ASSERT(m_state == State::WAIT_VERFIY_REQ);
	UNIT_INFO("svr rev verify req cmd=%x", cmd);
	UNIT_ASSERT(CMD_VERIFY == cmd);
	UNIT_ASSERT(msg == "verify");
	string rsp_msg = "verify_ok";
	ADFacadeMgr::Ins().NtfVerifyRet(id, true);
	ADFacadeMgr::Ins().CreateSession(id, [](const Session* sn) {
		UNIT_INFO("create session ok");
		});
	id.SendToClient(CMD_VERIFY, rsp_msg);
	m_state = State::WAIT_CLIENT_BEAT_TIME_OUT;

	auto f = [](const string& ip, uint16 port)
	{
		UNIT_INFO("GetClientAddr = %s %d", ip.c_str(), port);
		UNIT_ASSERT(ip == "127.0.0.1");
		UNIT_ASSERT(port>0);
	};
	ADFacadeMgr::Ins().GetClientAddr(id, f);
}

void HeartBeatSvr::OnClientDisCon(const proto::Session& sn)
{
	UNIT_ASSERT(m_state == State::WAIT_CLIENT_BEAT_TIME_OUT);
	m_state = State::END;
	UNIT_INFO("heartbeat svr end");
}



BDClient::BDClient(BaseFunTestMgr& mgr)
	:m_mgr(mgr)
{
	m_id = 0;
	m_state = State::END;
}

void BDClient::OnRecvMsg(uint32 cmd, const std::string& msg)
{
	if (CMD_VERIFY == cmd)
	{
		UNIT_INFO("verify ok");
	}
	else if (CMD_BROADCAST == cmd)
	{
		UNIT_ASSERT(msg == "CMD_BROADCAST");
		m_mgr.m_bd_svr.ClientRevBroadCmd();
	}
	else if (CMD_BROADCAST_PART == cmd)
	{
		UNIT_ASSERT(msg == "CMD_BROADCAST");
		m_mgr.m_bd_svr.ClientRevBroadPartCmd();
	}
	else
	{
		UNIT_INFO("unknow cmd =%x", cmd);
		UNIT_ASSERT(false);
	}
}

void BDClient::OnConnected()
{
	m_mgr.m_bd_svr.ClientOnConnected(m_id);
	SendStr(CMD_VERIFY, "verify");
}

void BDClient::OnDisconnected()
{
	UNIT_INFO("diconnect BDClient. idx=%d", m_id);
}

BDSvr::BDSvr(BaseFunTestMgr& mgr)
	: m_mgr(mgr)
{
	m_state = State::WAIT_ALL_CLIENT_CONNECT;
	m_broadpartCmd_cnt = 0;
	m_broadCmd_cnt = 0;
	m_tmp_num = 0;
}

void BDSvr::Start()
{
	UNIT_ASSERT(m_state == State::WAIT_ALL_CLIENT_CONNECT);
	UNIT_INFO("test broadcast, disconnect start");

	//all client connect init
	const std::vector<AccAddr>& ex_vec = CfgMgr::Ins().m_ex_vec;
	UNIT_ASSERT(ex_vec.size() > 1);
	uint32 idx = 0;
	for (auto& client : m_mgr.m_bd_client)
	{
		client.m_id = idx;
		if (idx == 1)
		{
			UNIT_ASSERT(client.ConnectInit(ex_vec[1].ip.c_str(), ex_vec[1].port));
		}
		else
		{
			UNIT_ASSERT(client.ConnectInit(ex_vec[0].ip.c_str(), ex_vec[0].port));
		}
		idx++;
	}
	m_client_set.clear();
}

void BDSvr::ClientOnConnected(uint32 idx)
{
	UNIT_ASSERT(m_state == State::WAIT_ALL_CLIENT_CONNECT);
	bool r = m_client_set.insert(idx).second;
	UNIT_ASSERT(r);
	if (m_client_set.size() == m_mgr.m_bd_client.size())
	{//all connect
		m_state = State::WAIT_ALL_VERIFY_OK;
		m_client_set.clear();
		UNIT_INFO("WAIT_ALL_VERIFY_OK");
	}
}

void BDSvr::ClientRevBroadCmd()
{
	UNIT_ASSERT(m_state == State::WAIT_BROADCAST);
	m_broadCmd_cnt++;
	CheckBroadEnd();
}

void BDSvr::ClientRevBroadPartCmd()
{
	UNIT_ASSERT(m_state == State::WAIT_BROADCAST);
	m_broadpartCmd_cnt++;
	CheckBroadEnd();
}

void BDSvr::CheckBroadEnd()
{
	UNIT_ASSERT(m_state == State::WAIT_BROADCAST);
	if (m_broadCmd_cnt == m_mgr.m_bd_client.size() && m_broadpartCmd_cnt == 1)
	{
		UNIT_INFO("finish broadcast test, start discon one client. cid=%llx", m_anyone_sid.cid);
		m_state = State::WAIT_DISCON_ONE;
		UNIT_ASSERT(m_anyone_sid.cid != 0);
		ADFacadeMgr::Ins().DisconClient(m_anyone_sid);
	}
}

void BDSvr::OnRegOK(uint32_t svrId)
{
}

void BDSvr::OnRevClientMsg(const Session& session, uint32 cmd, const std::string& msg)
{

}

void BDSvr::OnRevVerifyReq(const SessionId& id, uint32 cmd, const std::string& msg)
{
	UNIT_INFO("OnRevVerifyReq accId cid=%d %ld", id.accId, id.cid);
	UNIT_ASSERT(CMD_VERIFY == cmd);
	UNIT_ASSERT(msg == "verify");
	string rsp_msg = "verify_ok";
	ADFacadeMgr::Ins().NtfVerifyRet(id, true);
	auto onOk = [this](const Session *sn)
	{
		const SessionId &id = sn->id;
		UNIT_ASSERT(m_state == State::WAIT_ALL_VERIFY_OK);
		m_anyone_sid = id;
		bool r = m_clientSn_set.insert(id).second;
		UNIT_ASSERT(r);
		UNIT_INFO("verify SessionId: accId=%llx cid=%llx", id.accId, id.cid);
		if (m_clientSn_set.size() == m_mgr.m_bd_client.size())
		{//all verify ok
			UNIT_INFO("all verify ok");
			m_state = State::WAIT_BROADCAST;
			string s = "CMD_BROADCAST";
			ADFacadeMgr::Ins().BroadCastToClient(CMD_BROADCAST, s);
			std::vector<SessionId> vec_cid;
			vec_cid.push_back(id);
			ADFacadeMgr::Ins().BroadCastToClient(vec_cid, CMD_BROADCAST_PART, s);
			m_clientSn_set.clear();
		}
	};
	ADFacadeMgr::Ins().CreateSession(id, onOk);
	id.SendToClient(CMD_VERIFY, rsp_msg);

}

void BDSvr::OnClientDisCon(const proto::Session& sn)
{
	const SessionId& id = sn.id;
	UNIT_INFO("OnClientDisCon cid=%llx", id.cid);
	if (m_state == State::WAIT_DISCON_ONE)
	{
		UNIT_ASSERT(m_anyone_sid.cid == id.cid);
		UNIT_ASSERT(m_anyone_sid.accId == id.accId);
		UNIT_INFO("discon all");
		m_state = State::WAIT_DISCON_ALL;
		ADFacadeMgr::Ins().DisconAllClient();
		m_tmp_num = 0;
	}
	else if (m_state == State::WAIT_DISCON_ALL)
	{
		m_tmp_num++;
		if (m_tmp_num == 2)
		{
			m_state = State::END;
			UNIT_INFO("--------end--------");
			EventMgr::Ins().StopDispatch();
		}
	}
	else
	{
		UNIT_ASSERT(false);
	}
}




RouteClient::RouteClient(BaseFunTestMgr& mgr)
	:m_mgr(mgr)
{
	m_state = State::WAIT_VERIFY_OK;
	m_tmp1 = 0;
	m_tmp2 = 0;
}

void RouteClient::Start()
{
	UNIT_ASSERT(m_state == State::WAIT_VERIFY_OK);

	const std::vector<AccAddr>& ex_vec = CfgMgr::Ins().m_ex_vec;
	UNIT_ASSERT(ex_vec.size() > 1);
	UNIT_ASSERT(ConnectInit(ex_vec[0].ip.c_str(), ex_vec[0].port));
}


void RouteClient::OnRecvMsg(uint32 cmd, const std::string& msg)
{
	if (CMD_VERIFY == cmd)
	{
		UNIT_ASSERT(m_state == State::WAIT_VERIFY_OK);
		UNIT_INFO("verify ok. cid=%s", msg.c_str());
		m_snId.accId = 0;
		m_snId.cid = StrNum::ToUint64(msg);
		UNIT_ASSERT(m_snId.cid > 0);
		UNIT_INFO("m_snId.cid =%ld", m_snId.cid);
		m_state = State::WAIT_NORMAL_MSG_REV;
		SendStr(CMD_SVR1_MSG, "msg1");
	}
}

void RouteClient::OnConnected()
{
	UNIT_INFO("OnConnected");
	SendStr(CMD_VERIFY, "verify");
}


RouteSvr::RouteSvr(BaseFunTestMgr& mgr)
	: m_mgr(mgr)
{
}



void RouteSvr::OnRegOK(uint32_t svrId)
{

}

void RouteSvr::OnRevClientMsg(const Session& session, uint32 cmd, const std::string& msg)
{
	m_sid = session.id;
	UNIT_INFO("svr rev msg. m_svr_id =%d cmd=%x id.cid=%llx", m_svr_id, cmd, session.id.cid);
	UNIT_ASSERT(cmd == CMD_SVR1_MSG);
	
	if (1 == m_svr_id)
	{
		UNIT_ASSERT(msg == "msg1");
		ADFacadeMgr::Ins().DelSession(session.id);
		m_state = State::END;
		UNIT_INFO("------------end---------");
		EventMgr::Ins().StopDispatch();
	}
	else if (2 == m_svr_id)
	{
		UNIT_ASSERT(m_state == State::WAIT_ROUE_MSG_TO_SVR2);
		UNIT_ASSERT(msg == "msg2");
		m_state = State::END;
	}
}

void RouteSvr::OnRevVerifyReq(const SessionId& id, uint32 cmd, const std::string& msg)
{
	UNIT_ASSERT(CMD_VERIFY == cmd);
	UNIT_ASSERT(msg == "verify");
	UNIT_ASSERT(id.accId == 0);
	string rsp_msg = StrNum::NumToStr(id.cid);
	ADFacadeMgr::Ins().NtfVerifyRet(id, true);
	UNIT_ASSERT(1 == m_svr_id);
	ADFacadeMgr::Ins().CreateSession(id, [](const Session* sn) { LDEBUG("RouteSvr 1 create session"); });
	id.SendToClient(CMD_VERIFY, rsp_msg);
}
